/* 
 * File:   FreeList.cpp
 * Author: Usama, Max, Andy
 * 
 * Created on February 9, 2011, 1:02 PM
 */

#include "FreeList.h"
using namespace std;


FreeList::~FreeList() {
    delete m_seek;
}

FreeList::FreeList(const char *fileName, bool createFreeList)
: BlockLinkedList(){
//test
    if(fileName =="")throw new BlockGroupException;
    char* diskName = (char*)fileName;

    m_disk = new Disk(diskName,DEFAULT_NUMBER_OF_BLOCKS,Disk::DEFAULT_BLOCK_SIZE);
    
    if(createFreeList)
    {
        //Link all the blocks together
        for(int i = 0; i<FreeList::DEFAULT_NUMBER_OF_BLOCKS;i++)
        {
            Block bl = Block(Disk::DEFAULT_BLOCK_SIZE);
            bl.SetBlockNumber(i);
            bl.SetPointer(i+1,0);
            bl.Write(m_disk);
        }

        Block last = Block(DEFAULT_NUMBER_OF_BLOCKS-1,m_disk);
        last.SetPointer(-1,0);
        last.Write(m_disk);

        Block mother = Block(0,m_disk);
        mother.ClearBuffer();
        mother.SetPointer(1,Block::FREELIST_START_BLOCK_NUMBER);
        mother.SetPointer(DEFAULT_NUMBER_OF_BLOCKS-1,Block::FREELIST_END_BLOCK_NUMBER);
        mother.SetPointer(DEFAULT_NUMBER_OF_BLOCKS-1,Block::FREELIST_NUMBER_OF_BLOCKS);
        mother.Write(m_disk);
        m_startBlockNumber = 1;
        m_endBlockNumber = DEFAULT_NUMBER_OF_BLOCKS-1;
        m_numberOfBlocks = DEFAULT_NUMBER_OF_BLOCKS-1;
        m_seek = new Block(m_startBlockNumber,m_disk);

    }
    else
    {

        Block mother = Block(0,m_disk);
        m_startBlockNumber = mother.GetPointer(Block::FREELIST_START_BLOCK_NUMBER);
        m_endBlockNumber = mother.GetPointer(Block::FREELIST_END_BLOCK_NUMBER);
        m_numberOfBlocks = mother.GetPointer(Block::FREELIST_NUMBER_OF_BLOCKS);
        m_seek = new Block(m_startBlockNumber,m_disk);
    }
}

bool FreeList::Close (){
    bool success = false;
    Block mblock = Block(0,m_disk);
    mblock.SetPointer(m_startBlockNumber,Block::FREELIST_START_BLOCK_NUMBER);
    mblock.Write(m_disk);
    success = m_disk->Close();
    return success;
}

void FreeList::Return (BlockLinkedList *bll){
    cout<<"FreeList::Return(): ";
    if(bll->GetNumberOfBlocks() ==0){
        printf("Empty List!");
    }
    int blocks = bll->GetNumberOfBlocks();
    int blocksAdded = 0;
    do{
        //bll->Rewind();
        Block *temp = bll->UnlinkBlock();
        this->AddBlock(temp);
        delete temp;
        blocksAdded++;
    }while(bll->GetNumberOfBlocks() != 0);
    Block mblk = Block(0,m_disk);
    mblk.SetPointer(m_endBlockNumber,Block::FREELIST_END_BLOCK_NUMBER);
    mblk.SetPointer(m_numberOfBlocks,Block::FREELIST_NUMBER_OF_BLOCKS);
    mblk.Write(m_disk);
    if(blocks == blocksAdded)
        printf("Successfully added %d blocks to FreeList",blocks);
    else printf("Failure! Only %d blocks added",blocksAdded);
}

BlockGroup * FreeList::CreateNew (){
    //printf("FreeList::CreateNew: ");
    if(m_numberOfBlocks ==0){
        printf("FreeList Empty!\n");
        return NULL;
    }
    Block* forBG = this->UnlinkBlock();
    int num = forBG->GetBlockNumber();
    delete forBG;
    BlockGroup* bg = new BlockGroup(num,num,1,this);
    return bg;
}